Skip to content

Conversation

@jlebon
Copy link
Contributor

@jlebon jlebon commented Jun 19, 2025

If we're pulling by digest and the pullspec already exists, then there's no need to reach out to the registry or even spawn skopeo.

Detect this case and exit early in the pull code.

This allows RHCOS to conform better to the PinnedImageSet API[1], where the expectation is that once an image is pulled, the registry will not be contacted again. In a future with unified storage, the MCO's pre-pull would work just the same for the RHCOS image as any other.

Framing this more generally: this patch allows one to pre-pull an image into the store, and making the later deployment operation be fully offline. E.g. this could be used to implement a bootc switch --download-only option.

[1] https://github.com/openshift/enhancements/blob/26ce3cd8a0c7ce650e73bc5393a3605022cb6847/enhancements/machine-config/pin-and-pre-load-images.md

@jlebon
Copy link
Contributor Author

jlebon commented Jun 19, 2025

If we do this, I'll probably add the same to rpm-ostree (... will be nice once we get to coreos/rpm-ostree#4994).

Also this needs a test.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request optimizes image pulls by short-circuiting the process if the image already exists locally, improving efficiency. The changes are well-structured and the logic is sound.

Copy link
Collaborator

@cgwalters cgwalters left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@cgwalters
Copy link
Collaborator

  • I downgraded the println! to a tracing::debug! since I think silence-is-golden in this case
  • Now that I look closer I think this would be better in the ostree-ext code

@jlebon
Copy link
Contributor Author

jlebon commented Jun 23, 2025

I downgraded the println! to a tracing::debug! since I think silence-is-golden in this case

WFM. Just to note though, this was an attempt to match the "No changes" code lower down for the AlreadyPresent case. (But using a different string to make the cases distinguishable for e.g. testing/debugging.)

Now that I look closer I think this would be better in the ostree-ext code

Heh, that was actually what I did at first, trying to make it directly part of ImageImporter::prepare() since it's what already returns AlreadyPresent. The problem is that new_importer() already forks skopeo, and crucially does OpenImage which will reach out to the registry, even before we get there.

Or do you mean just shoving that code into a non-member utility function in ostree-ext?

@jlebon
Copy link
Contributor Author

jlebon commented Jun 23, 2025

Alternatively I guess we switch proxy_img to be an Option<OpenedImage> and delay initialization until prepare().

@cgwalters cgwalters marked this pull request as draft June 23, 2025 13:24
@cgwalters
Copy link
Collaborator

Yep let me take this one

Prep for avoiding any operations in pull-by-digest mode.

Signed-off-by: Colin Walters <[email protected]>
Prep for pull-by-digest noop.

Signed-off-by: Colin Walters <[email protected]>
@cgwalters cgwalters marked this pull request as ready for review June 23, 2025 14:00
@cgwalters
Copy link
Collaborator

OK I redid this, can you review?

If we're pulling by digest and the pullspec already exists, then there's
no need to reach out to the registry or even spawn skopeo.

Detect this case and exit early in the pull code.

This allows RHCOS to conform better to the PinnedImageSet API[1], where
the expectation is that once an image is pulled, the registry will not
be contacted again. In a future with unified storage, the MCO's pre-pull
would work just the same for the RHCOS image as any other.

Framing this more generally: this patch allows one to pre-pull an
image into the store, and making the later deployment operation be
fully offline. E.g. this could be used to implement a `bootc switch
--download-only` option.

[1] https://github.com/openshift/enhancements/blob/26ce3cd8a0c7ce650e73bc5393a3605022cb6847/enhancements/machine-config/pin-and-pre-load-images.md

Signed-off-by: Colin Walters <[email protected]>
Co-authored-by: Colin Walters <[email protected]>
Signed-off-by: Colin Walters <[email protected]>
}
Some(previous_state)
} else {
None
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be previous_state?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, because we destructured above - here we know previous_state is None.


// Parse the target reference to see if it's a digested pull
let target_reference = self.imgref.imgref.name.parse::<Reference>().ok();
let previous_state = if let Some(target_digest) = target_reference
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah... I know why we do this (to not lose ownership of previous_state). What I had done in my first attempt which was in this same spot was:

let oci_ref = self.imgref.imgref.name.parse::<OciReference>().ok();
if let Some(digest) = oci_ref.as_ref().and_then(|oci_ref| oci_ref.digest()) {
    let digest = Digest::from_str(digest)?;
    if previous_state.as_ref()
        .map(|state| state.manifest_digest == digest)
        .unwrap_or_default()
    {
        // SAFETY: It can't be None if the map().unwrap() above gave
        // true. We do it this way so that we only consume the Option if
        // we return here. That way it can be reused below if not.
        return Ok(PrepareResult::AlreadyPresent(previous_state.unwrap()));
    }
}

which yes, does an unwrap (though is guaranteed safe), but has a cleaner flow.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That version is definitely a lot cleaner to read, but I usually try pretty hard to avoid unwrap().

@jlebon
Copy link
Contributor Author

jlebon commented Jun 23, 2025

I can't officially LGTM, but LGTM. Thanks for picking this up! Having it in ostree-ext means rpm-ostree should also get this behaviour.

Copy link
Collaborator

@jeckersb jeckersb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM on a cursory glance, mostly trusting @jlebon's +1 and making it official 😄

@cgwalters cgwalters merged commit 350fb40 into bootc-dev:main Jun 23, 2025
31 of 34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants